<?php

namespace common\service;


use common\model\EpisodeAllocationModel;
use common\exception\LogicException;
use common\model\EntityModel;
use common\model\OrderModel;
use common\model\UserModel;
use think\module\Module;
use support\ErrorCode;
use think\Exception;

class OutsideTaskReviewWorkflowService extends ReviewWorkflowService
{

    /**
     * 外部审核流起点
     * @return string
     */
    public function getStartRoleCode()
    {
        return TaskService::HEADMAN_CODE;
    }

    /**
     * 匹配审核预设配置用户
     * @param $reviewPreSetConfig
     * @param string $role
     * @param array $extraUserList
     * @return false|mixed
     */
    private function matchPresetUser($reviewPreSetConfig, string $role, array $extraUserList)
    {
        $presetUserId = $reviewPreSetConfig[$role] ?? 0;
        if ($presetUserId <= 0) {
            return false;
        }
        if (empty($extraUserList[$presetUserId])) {
            return false;
        }
        return $extraUserList[$presetUserId];
    }

    /**
     * 查询任务审批流
     * @param int $taskId
     * @param int $orderId
     * @return array
     * @throws Exception
     */
    public function selectReview(int $taskId, int $orderId)
    {
        $order = model(OrderModel::class)->find($orderId);
        $orderService = OrderService::getInstance();
        $sourceTask = $orderService->getSourceTaskByTaskId($taskId);
        if (empty($sourceTask)) {
            throw new LogicException('partya already withdraw this task', ErrorCode::PARTYA_ALREADY_WITHDRAW_TASK);
        }
        $taskFields = [
            "t.id", "t.name", "t.code", "t.project_id", "t.tenant_id", "t.entity_id", "t.step_id", "t.assignee", "t.executor", 't.department_id',
            'e.step_workflow_id', 'e.initial_episode_code',
        ];
        $taskData = model(EntityModel::class)
            ->alias("e")
            ->join('task t on e.id = t.entity_id')
            ->field($taskFields)
            ->where(['t.id' => $taskId])
            ->find();
        if (empty($taskData)) {
            throw_strack_exception("task not found ", ErrorCode::TASK_NOT_FOUND);
        }
        $sourceTaskData = model(EntityModel::class)->alias("e")->join('task t on e.id = t.entity_id')->field($taskFields)->where(['t.id' => $sourceTask['id']])->find();
        try {
            // 原始任务审核流配置信息
            $projectReviewWorkflowRelation = $this->getTaskReviewWorkflowRelationConfig($sourceTaskData['id'], $sourceTaskData['project_id'], $sourceTaskData['step_workflow_id'], $sourceTaskData['step_id']);
        } catch (LogicException $e) {
            if ($e->getCode() == ErrorCode::REVIEW_WORKFLOW_CONFIG_NOT_FOUND) {
                return null;
            }
            throw $e;
        }

        //初始集查询
        $episodeFilter = [
            'code' => $sourceTaskData['initial_episode_code'],
            'project_id' => $sourceTaskData['project_id'],
            'module_id' => Module::$moduleDictData['module_index_by_code']['episode']['id'],
        ];
        $episode = model(EntityModel::class)->where($episodeFilter)->field("id")->find();

        //审批流查询
        $reviewFilter = [
            'id' => $projectReviewWorkflowRelation['review_workflow_id'],
            'active' => "yes",
            'is_deleted' => "no",
        ];
        list($nodesData, $promoter, $reviewers,) = $this->getParsedWorkflow($reviewFilter);

        $startRoleCode = $this->getStartRoleCode();
        $reviewerRoles = array_column($reviewers, 'role');

        //用户当前角色 不在节点里
        if (!in_array($startRoleCode, $reviewerRoles) && $startRoleCode != $promoter) {
            throw new LogicException("your role [{$startRoleCode}] not in this workflow", ErrorCode::CURRENT_ROLE_NOT_IN_THE_NODE);
        }

        try {
            $roleInfo = teamones_request('teamones-im', 'role/select', [
                "param" => [
                    "filter" => [
                        "role.code" => ['-in', implode(',', $reviewerRoles)],
                    ],
                    "fields" => "role.id,role.name,role.code",
                ],
            ])['data']['rows'];
        } catch (\Throwable $e) {
            throw new LogicException("get role from remote failed", ErrorCode::GET_ROLE_FROM_REMOTE_FAILED);
        }

        if (empty($roleInfo)) {
            throw new LogicException("has not enough users to execute step check workflow", ErrorCode::NOT_ENOUGH_USERS_TO_EXECUTE_STEP_CHECK_WORKFLOW);
        }

        $roleNameMap = array_column($roleInfo, 'name', 'code');
        $reviewersData = [];
        $leftReviewerRoles = $reviewerRoles;
        $tenantService = TenantService::getInstance();
        //远端获取租户用户和角色信息
        try {
            $selectDepartmentUserListFilter = [
                "param" => [
                    "filter" => [
                        'tenant_id' => $order['from_tenant_id'],
                        "role_code" => implode(',', $leftReviewerRoles),
                    ],
                ],
            ];
            $users = $tenantService->selectDepartmentUser($order['from_tenant_id'], $selectDepartmentUserListFilter);
            $users = $users['rows'];
        } catch (\Exception $e) {
            trace(format_exception_info($e), 'ERR');
            throw new LogicException("get user from remote failed" . format_exception_info($e), ErrorCode::GET_ROLE_FROM_REMOTE_FAILED);
        }
        if (empty($users)) {
            throw new LogicException("has not enough users to execute step check workflow", ErrorCode::NOT_ENOUGH_USERS_TO_EXECUTE_STEP_CHECK_WORKFLOW);
        }
        $usersMapByUserId = array_column($users, null, 'user_id');

        $extraUserIdList = [$order['party_a_person_in_charge'] => $order['party_a_person_in_charge'], $order['party_a_resp_producer_id'] => $order['party_a_resp_producer_id'], $order['party_b_resp_producer_id'] => $order['party_b_resp_producer_id']];
        $userQueryFields = 'id,name,avatar,phone,email,union_id';
        // 剧集分配信息查询
        $episodeAllocationFilter = [
            'project_id' => $sourceTaskData['project_id'],
            'role_code' => ["IN", implode(',', $leftReviewerRoles)],
            'entity_id' => $episode['id'],
        ];
        //导演  查询剧集分配
        $episodeAllocation = model(EpisodeAllocationModel::class)->where($episodeAllocationFilter)->select();
        $episodeAllocationGroupedByRole = [];
        if (!empty($episodeAllocation)) {
            $extraUserIdList += array_column($episodeAllocation, 'user_id', 'user_id');
            $episodeAllocationGroupedByRole = array_group_by($episodeAllocation, 'role_code');
        }

        // 审核流预设人员配置解析
        $reviewPreSetConfig = $projectReviewWorkflowRelation['review_node_config'] ?? [];
        if (!empty($reviewPreSetConfig)) {
            $reviewPreSetConfigUserIdList = array_column($reviewPreSetConfig, 'user_id', 'user_id');
            $reviewPreSetConfig = array_column($reviewPreSetConfig, 'user_id', 'role_code');
            $extraUserIdList += $reviewPreSetConfigUserIdList;
        }
        $extraUserList = [];
        if (!empty($extraUserIdList)) {
            $extraUserList = model(UserModel::class)->where(['id' => ['IN', array_values($extraUserIdList)]])->field($userQueryFields)->select();
            $extraUserList = array_column($extraUserList, null, 'id');
        }

        $role = null;
        $roleCodeFilter = function ($item) use (&$role) {
            if (empty($item['role_info'])) {
                return false;
            }
            foreach ($item['role_info'] as $roleInfo) {
                if ($roleInfo['code'] === $role) {
                    return true;
                }
            }
            return false;
        };

        foreach ($reviewerRoles as $role) {
            $tmpReviewerData = [
                'role_name' => $roleNameMap[$role],
                "role_code" => $role,
                "user_info" => [
                ],
                "skip" => 0,
                'user_id' => 0,
            ];
            // 只有组长后置检查项目预设配置
            if ($role !== TaskService::HEADMAN_CODE) {
                trace($role . ' 角色 先进行项目审核配置检查', 'DEBUG');
                $matchPresetUser = $this->matchPresetUser($reviewPreSetConfig, $role, $extraUserList);
                if (!empty($matchPresetUser)) {
                    $tmpReviewerData['user_info'][] = $matchPresetUser;
                    $reviewersData[] = $tmpReviewerData;
                    continue;
                }
            }

            $reviewerUsers = [];
            //处理特殊情况
            switch ($role) {
                case TaskService::HEADMAN_CODE:
                    //组长  根据订单负责组长id筛选
                    $personInCharge = $extraUserList[$order['party_a_person_in_charge']] ?? null;
                    if (!empty($personInCharge) && isset($usersMapByUserId[$personInCharge['union_id']])) {
                        trace($role . ' 角色 匹配到订单组长负责人', 'DEBUG');
                        $reviewerUsers[] = $usersMapByUserId[$personInCharge['union_id']];
                    } else {
                        // 检查项目预设配置
                        $matchPresetUser = $this->matchPresetUser($reviewPreSetConfig, $role, $extraUserList);
                        if (!empty($matchPresetUser)) {
                            trace($role . ' 角色 匹配到项目配置的审核人', 'DEBUG');
                            $tmpReviewerData['user_info'][] = $matchPresetUser;
                            $reviewersData[] = $tmpReviewerData;
                            continue 2;
                        } else {
                            trace($role . ' 角色 直接在租户里进行角色筛选', 'DEBUG');
                            $reviewerUsers = array_filter($users, $roleCodeFilter);
                        }
                    }
                    break;
                case TaskService::PRODUCER_CODE:
                    //制片人  直接找制片人 订单甲方制片
                    $producerInCharge = $extraUserList[$order['party_a_resp_producer_id']] ?? null;
                    if (empty($producerInCharge)) {
                        $reviewerUsers = array_filter($users, $roleCodeFilter);
                    } else {
                        if (isset($usersMapByUserId[$producerInCharge['union_id']])) {
                            $reviewerUsers[] = $usersMapByUserId[$producerInCharge['union_id']];
                        }
                    }
                    break;
                case TaskService::DIRECTOR_CODE:
                case TaskService::QA_CODE:
                case TaskService::ARTILIST_CODE:
                    //艺术家或者其他角色 直接进默认
                default:
                    // 默认处理 优先检查剧集分配数据 中是否包含
                    // 当前任务实体是否存在初始集
                    if (!empty($episode)) {
                        //导演  查询剧集分配
                        $episodeAllocationList = $episodeAllocationGroupedByRole[$role] ?? [];
                        if (!empty($episodeAllocationList)) {
                            foreach ($episodeAllocationList as $episodeAllocation) {
                                if (isset($extraUserList[$episodeAllocation['user_id']])) {
                                    $tmpReviewerData['user_info'][] = $extraUserList[$episodeAllocation['user_id']];
                                }
                            }
                            if (count($tmpReviewerData['user_info']) > 0) {
                                $reviewersData[] = $tmpReviewerData;
                                continue 2;
                            }
                        }
                    }

                    //查不到用户 就从租户里查
                    $reviewerUsers = array_filter($users, $roleCodeFilter);

            }

            if (count($reviewerUsers) == 0) {
                throw new LogicException("outside to inside can`t found a {$role}", ErrorCode::ROLE_NOT_FOUND);
            } else if (count($reviewerUsers) == 1) {
                $tmpReviewerData['user_info'][] = array_shift($reviewerUsers)['saas_user'];
            } else {
                $tmpReviewerData['user_info'] = array_column($reviewerUsers, 'saas_user');
            }
            $reviewersData[] = $tmpReviewerData;
        }

        return [
            "review_workflow" => $nodesData,
            "matched_data" => [
                'promoter' => $promoter,
                'reviewers' => $reviewersData,
            ],
        ];
    }
}
